#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
监控项对话框模块 - 用于配置监控项
"""

import logging
import json
import os
from typing import Dict, List, Any, Optional
from PyQt5.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, 
    QLineEdit, QPushButton, QFormLayout, QDialogButtonBox,
    QComboBox, QSpinBox, QTabWidget, QWidget, QTextEdit,
    QCheckBox, QMessageBox, QTableWidget, QTableWidgetItem,
    QHeaderView, QFileDialog, QGroupBox, QAbstractItemView,
    QRadioButton, QButtonGroup
)
from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtGui import QColor, QIntValidator

# 导入Excel处理库
try:
    import pandas as pd
    PANDAS_AVAILABLE = True
except ImportError:
    PANDAS_AVAILABLE = False

from src.zabbix_api import ZabbixAPI

logger = logging.getLogger(__name__)

class ItemDialog(QDialog):
    """监控项配置对话框"""
    
    def __init__(self, api: ZabbixAPI, hosts: List[Dict[str, Any]], parent=None):
        """
        初始化监控项对话框
        
        Args:
            api (ZabbixAPI): Zabbix API客户端
            hosts (List[Dict[str, Any]]): 主机列表
            parent: 父窗口
        """
        super().__init__(parent)
        self.api = api
        self.hosts = hosts
        self.item_types = api.get_item_types()
        self.value_types = api.get_value_types()
        
        # 获取主机的IP地址和端口
        self.host_ips = self.get_host_ip_addresses()
        
        self.setup_ui()
    
    def get_host_ip_addresses(self):
        """获取主机的IP地址、端口和SNMP版本"""
        host_ips = {}  # 存储主机ID到IP地址的映射
        host_ports = {}  # 存储主机ID到端口的映射
        host_snmp_versions = {}  # 存储主机ID到SNMP版本的映射
        
        try:
            # 获取所有主机ID
            hostids = [host.get('hostid') for host in self.hosts if host.get('hostid')]
            
            if not hostids:
                return host_ips
                
            logger.info(f"正在获取 {len(hostids)} 台主机的IP地址、端口和SNMP版本...")
            
            # 使用hostinterface.get API获取主机接口
            try:
                # 尝试不同的API调用方式
                if hasattr(self.api, 'hostinterface') and hasattr(self.api.hostinterface, 'get'):
                    interfaces = self.api.hostinterface.get(
                        hostids=hostids,
                        output="extend",
                        selectDetails="extend"  # 获取详细信息，包括SNMP版本
                    )
                    logger.info("使用 api.hostinterface.get() 获取主机接口")
                elif hasattr(self.api, 'do_request'):
                    interfaces_resp = self.api.do_request('hostinterface.get', {
                        'hostids': hostids,
                        'output': "extend",
                        'selectDetails': "extend"  # 获取详细信息，包括SNMP版本
                    })
                    if isinstance(interfaces_resp, dict) and "result" in interfaces_resp:
                        interfaces = interfaces_resp["result"]
                    else:
                        interfaces = interfaces_resp
                    logger.info("使用 api.do_request() 获取主机接口")
                elif hasattr(self.api, 'auth') and hasattr(self.api, 'url'):
                    # 直接使用JSON-RPC调用
                    import requests
                    json_request = {
                        "jsonrpc": "2.0",
                        "method": "hostinterface.get",
                        "params": {
                            "output": "extend",
                            "selectDetails": "extend",  # 获取详细信息，包括SNMP版本
                            "hostids": hostids
                        },
                        "auth": self.api.auth,
                        "id": 1
                    }
                    
                    # 尝试使用json_request方法或直接HTTP请求
                    if hasattr(self.api, 'json_request'):
                        response = self.api.json_request(json_request)
                        interfaces = response.get("result", [])
                        logger.info("使用 api.json_request() 获取主机接口")
                    else:
                        url = self.api.url
                        headers = {'Content-Type': 'application/json-rpc'}
                        r = requests.post(url, json=json_request, headers=headers)
                        response = r.json()
                        interfaces = response.get("result", [])
                        logger.info("使用直接HTTP请求获取主机接口")
                else:
                    logger.warning("无法找到合适的方法获取主机接口")
                    return host_ips
                
                # 处理接口数据
                if interfaces:
                    logger.info(f"找到 {len(interfaces)} 个主机接口")
                    for interface in interfaces:
                        hostid = interface.get('hostid')
                        ip = interface.get('ip')
                        port = interface.get('port')
                        details = interface.get('details', {})
                        
                        # 处理details可能是字符串的情况
                        if isinstance(details, str):
                            try:
                                details = json.loads(details)
                            except json.JSONDecodeError:
                                details = {}
                        
                        # 获取SNMP版本
                        snmp_version = None
                        if interface.get('type') == '2':  # SNMP接口
                            version = details.get('version')
                            if version:
                                snmp_version = f"SNMPv{version}"
                                # 如果是SNMPv3，添加详细信息
                                if version == '3':
                                    auth_protocol = details.get('authprotocol', '')
                                    priv_protocol = details.get('privprotocol', '')
                                    security_name = details.get('securityname', '')
                                    
                                    auth_info = []
                                    if security_name:
                                        auth_info.append(f"用户:{security_name}")
                                    if auth_protocol:
                                        auth_info.append(f"认证:{auth_protocol.upper()}")
                                    if priv_protocol:
                                        auth_info.append(f"加密:{priv_protocol.upper()}")
                                    
                                    if auth_info:
                                        snmp_version += f" ({', '.join(auth_info)})"
                        
                        if hostid:
                            if hostid not in host_ips:
                                host_ips[hostid] = []
                            if ip:
                                host_ips[hostid].append(ip)
                        
                            # 存储端口信息
                            if port:
                                if hostid not in host_ports:
                                    host_ports[hostid] = []
                                host_ports[hostid].append(port)
                                
                                # 存储SNMP版本信息
                                if snmp_version and port == "161":
                                    if hostid not in host_snmp_versions:
                                        host_snmp_versions[hostid] = []
                                    host_snmp_versions[hostid].append(snmp_version)
                                
                                # 更新主机对象的端口信息
                                for host in self.hosts:
                                    if host.get('hostid') == hostid:
                                        host['port'] = port
                                        
                                        # 标记主机类型
                                        if port == "10050":
                                            host['agent_type'] = "zabbix"
                                        elif port == "161":
                                            host['agent_type'] = "snmp"
                                            if snmp_version:
                                                host['snmp_version'] = snmp_version
                                        break
                    
                    logger.info(f"处理完成，为 {len(host_ips)} 台主机找到了IP地址、端口和SNMP版本")
            except Exception as api_err:
                logger.error(f"通过API获取主机接口信息失败: {str(api_err)}")
            except Exception as e:
                logger.error(f"获取主机IP地址和端口时出错: {str(e)}")
        
        self.host_ports = host_ports  # 保存端口信息
        self.host_snmp_versions = host_snmp_versions  # 保存SNMP版本信息
        return host_ips
    
    def setup_ui(self):
        """设置UI界面"""
        self.setWindowTitle("创建监控项")
        self.resize(800, 600)
        self.setModal(True)
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建表格显示选中的主机
        host_group = QGroupBox("已选主机:")
        host_layout = QVBoxLayout(host_group)
        host_layout.setContentsMargins(5, 10, 5, 5)  # 减小边距
        
        self.host_table = QTableWidget()
        self.host_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.host_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.host_table.setColumnCount(6)  # 增加了一列用于显示SNMP协议版本
        self.host_table.setHorizontalHeaderLabels(["主机ID", "主机名", "可见名称", "IP地址", "端口", "SNMP版本"])
        self.host_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.host_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeToContents)
        self.host_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.Stretch)  # 设置SNMP版本列为自适应宽度
        
        # 设置最小宽度以确保有足够的空间显示详细信息
        self.host_table.setColumnWidth(5, 250)  # 为SNMP版本列设置一个合适的初始宽度
        
        # 设置最小高度，增加高度与触发器对话框一致
        self.host_table.setMinimumHeight(180)
        
        # 添加选择变更事件，用于检测SNMP设备
        self.host_table.itemSelectionChanged.connect(self.on_host_selection_changed)
        
        host_layout.addWidget(self.host_table)
        
        # 填充主机表格
        self.host_table.setRowCount(len(self.hosts))
        
        # 预先加载所有主机的完整信息 - 构建hostid->host和name->host映射表
        self.host_info_map = {}  # 主机ID -> 完整信息
        self.name_to_host_map = {}  # 可见名称 -> 技术名称
        self.load_complete_host_info()
        
        # 存储端口信息以便后续使用
        port_161_found = False
        first_host_port = None
        
        for i, host in enumerate(self.hosts):
            hostid = host.get("hostid", "")
            
            # 主机ID
            self.host_table.setItem(i, 0, QTableWidgetItem(hostid))
            
            # IP地址
            ip_text = ", ".join(self.host_ips.get(hostid, [])) if hostid in self.host_ips else "-"
            self.host_table.setItem(i, 1, QTableWidgetItem(ip_text))
            
            # 主机名称（技术名称）
            technical_name = host.get("host", "")
            # 如果在原始数据中找不到技术名称，尝试从映射表中获取
            if not technical_name and hostid in self.host_info_map:
                technical_name = self.host_info_map[hostid].get("host", "")
            
            # 如果仍然找不到，尝试从visible_name映射获取
            if not technical_name:
                visible_name = host.get("name", "")
                if visible_name in self.name_to_host_map:
                    technical_name = self.name_to_host_map[visible_name]
            
            tech_name_item = QTableWidgetItem(technical_name)
            self.host_table.setItem(i, 2, tech_name_item)
            
            # 可见名称 - 优先使用从API获取的完整信息
            visible_name = ""
            if hostid in self.host_info_map:
                visible_name = self.host_info_map[hostid].get("name", "")
            
            # 如果在映射表中找不到，再使用原始数据中的name字段
            if not visible_name:
                visible_name = host.get("name", "")
                
            self.host_table.setItem(i, 3, QTableWidgetItem(visible_name))
            
            # 端口号
            port_text = ""
            if hasattr(self, 'host_ports') and hostid in self.host_ports:
                port_text = ", ".join(self.host_ports.get(hostid, []))
            elif host.get("port"):
                port_text = host.get("port")
                
            port_item = QTableWidgetItem(port_text)
            
            # 为不同类型的端口设置不同的背景色
            if port_text == "10050":
                port_item.setBackground(QColor(230, 255, 230))  # 淡绿色 - Zabbix Agent
            elif port_text == "161":
                port_item.setBackground(QColor(230, 230, 255))  # 淡蓝色 - SNMP
                port_161_found = True
            
            self.host_table.setItem(i, 4, port_item)
            
            # 记录第一个主机的端口（用于后续自动设置客户端类型）
            if i == 0 and port_text:
                first_host_port = port_text
            
            # SNMP版本
            snmp_version_text = ""
            if hasattr(self, 'host_snmp_versions') and hostid in self.host_snmp_versions:
                snmp_version_text = ", ".join(self.host_snmp_versions.get(hostid, []))
            elif host.get("snmp_version"):
                snmp_version_text = host.get("snmp_version")
                
            snmp_version_item = QTableWidgetItem(snmp_version_text)
            
            # 为不同的SNMP版本设置不同的显示效果
            if "SNMPv3" in snmp_version_text:
                snmp_version_item.setBackground(QColor(255, 230, 210))  # 淡橙色 - SNMPv3
                snmp_version_item.setForeground(QColor(170, 0, 0))       # 深红色文字
            elif "SNMPv2" in snmp_version_text:
                snmp_version_item.setBackground(QColor(210, 230, 255))  # 淡蓝色 - SNMPv2
            
            self.host_table.setItem(i, 5, snmp_version_item)
            
            # 如果技术名称仍然为空，设置该行背景色为浅红色，提示有问题
            if not technical_name:
                for col in range(6):
                    self.host_table.item(i, col).setBackground(QColor(255, 220, 220))
        
        # 将主机组添加到主布局，设置拉伸系数为4，与触发器对话框保持一致
        main_layout.addWidget(host_group, 4)
        
        # 创建标签页面
        tab_widget = QTabWidget()
        
        # 基本信息标签页
        basic_tab = QWidget()
        basic_layout = QFormLayout(basic_tab)
        
        # 监控项名称
        self.name_edit = QLineEdit()
        basic_layout.addRow("名称:", self.name_edit)
        
        # 键值
        self.key_edit = QLineEdit()
        self.key_edit.textChanged.connect(self.on_key_changed)
        basic_layout.addRow("键值:", self.key_edit)
        
        # 客户端类型
        self.type_combo = QComboBox()
        for type_id, type_name in self.item_types.items():
            self.type_combo.addItem(type_name, type_id)
        basic_layout.addRow("客户端类型:", self.type_combo)
        
        # 信息类型
        self.value_type_combo = QComboBox()
        for type_id, type_name in self.value_types.items():
            self.value_type_combo.addItem(type_name, type_id)
        basic_layout.addRow("信息类型:", self.value_type_combo)
        
        # SNMP OID 配置区域 (只在选择SNMP类型时显示)
        self.snmp_group = QGroupBox("SNMP OID 配置")
        self.snmp_group.setVisible(False)  # 默认隐藏
        snmp_layout = QFormLayout(self.snmp_group)
        
        # OID 输入框与SNMP版本信息布局
        oid_layout = QHBoxLayout()
        
        # OID输入框
        self.oid_edit = QLineEdit()
        self.oid_edit.setPlaceholderText("输入OID，例如: .1.3.6.1.2.1.1.1.0")
        self.oid_edit.textChanged.connect(self.validate_oid)
        oid_layout.addWidget(self.oid_edit)
        
        # 添加OID帮助按钮
        self.oid_help_button = QPushButton("?")
        self.oid_help_button.setMaximumWidth(30)
        self.oid_help_button.clicked.connect(self.show_oid_help)
        oid_layout.addWidget(self.oid_help_button)
        
        # 添加SNMP版本标签 - 直接跟在OID输入框右侧
        self.snmp_version_label = QLabel("未选择SNMP设备")
        self.snmp_version_label.setStyleSheet("color: #555555; font-style: italic; margin-left: 10px; padding: 2px 5px;")
        # 确保标签有足够的可见性
        self.snmp_version_label.setMinimumWidth(200)
        oid_layout.addWidget(self.snmp_version_label)
        
        # 添加弹性空间，确保标签紧跟在OID输入框和帮助按钮之后
        oid_layout.addStretch(1)
        
        snmp_layout.addRow("OID:", oid_layout)
        
        # 添加SNMP社区名称输入框
        self.community_edit = QLineEdit()
        self.community_edit.setPlaceholderText("默认: public")
        self.community_edit.setText("public")
        snmp_layout.addRow("社区名称:", self.community_edit)
        
        # 添加SNMPv3配置区域
        self.snmpv3_group = QGroupBox("SNMPv3 配置")
        self.snmpv3_group.setVisible(False)  # 默认隐藏
        snmpv3_layout = QFormLayout(self.snmpv3_group)
        
        # 安全级别
        self.snmpv3_security_level_combo = QComboBox()
        self.snmpv3_security_level_combo.addItem("noAuthNoPriv (无认证无加密)", 0)
        self.snmpv3_security_level_combo.addItem("authNoPriv (认证无加密)", 1)
        self.snmpv3_security_level_combo.addItem("authPriv (认证加密)", 2)
        self.snmpv3_security_level_combo.setCurrentIndex(2)  # 默认选择最高安全级别
        snmpv3_layout.addRow("安全级别:", self.snmpv3_security_level_combo)
        
        # 安全名称
        self.snmpv3_security_name_edit = QLineEdit()
        snmpv3_layout.addRow("安全名称:", self.snmpv3_security_name_edit)
        
        # 认证协议
        self.snmpv3_auth_protocol_combo = QComboBox()
        self.snmpv3_auth_protocol_combo.addItem("MD5", "md5")
        self.snmpv3_auth_protocol_combo.addItem("SHA", "sha")
        snmpv3_layout.addRow("认证协议:", self.snmpv3_auth_protocol_combo)
        
        # 认证密码
        self.snmpv3_auth_passphrase_edit = QLineEdit()
        self.snmpv3_auth_passphrase_edit.setEchoMode(QLineEdit.Password)
        snmpv3_layout.addRow("认证密码:", self.snmpv3_auth_passphrase_edit)
        
        # 加密协议
        self.snmpv3_priv_protocol_combo = QComboBox()
        self.snmpv3_priv_protocol_combo.addItem("DES", "des")
        self.snmpv3_priv_protocol_combo.addItem("AES", "aes")
        snmpv3_layout.addRow("加密协议:", self.snmpv3_priv_protocol_combo)
        
        # 加密密码
        self.snmpv3_priv_passphrase_edit = QLineEdit()
        self.snmpv3_priv_passphrase_edit.setEchoMode(QLineEdit.Password)
        snmpv3_layout.addRow("加密密码:", self.snmpv3_priv_passphrase_edit)
        
        # 添加SNMPv3配置到SNMP配置区域
        snmp_layout.addRow("", self.snmpv3_group)
        
        # 添加SNMP配置区域到基本信息标签页
        basic_layout.addRow("", self.snmp_group)
        
        # 更新间隔
        self.delay_spin = QSpinBox()
        self.delay_spin.setMinimum(1)
        self.delay_spin.setMaximum(86400)  # 1天
        self.delay_spin.setValue(60)  # 默认60秒
        self.delay_spin.setSuffix("s")  # 添加单位后缀
        basic_layout.addRow("更新间隔:", self.delay_spin)
        
        # 历史存储周期
        self.history_spin = QSpinBox()
        self.history_spin.setMinimum(1)
        self.history_spin.setMaximum(99999)
        self.history_spin.setValue(90)  # 默认90天
        basic_layout.addRow("历史存储周期(天):", self.history_spin)
        
        # 趋势存储周期
        self.trends_spin = QSpinBox()
        self.trends_spin.setMinimum(0)
        self.trends_spin.setMaximum(99999)
        self.trends_spin.setValue(365)  # 默认365天
        basic_layout.addRow("趋势存储周期(天):", self.trends_spin)
        
        # 将描述区域改为单行
        self.description_edit = QLineEdit()  # 使用QLineEdit代替QTextEdit
        self.description_edit.setPlaceholderText("输入描述信息...")
        basic_layout.addRow("描述:", self.description_edit)
        
        # 添加基本信息标签页
        tab_widget.addTab(basic_tab, "基本信息")
        
        # 批量创建标签页
        batch_tab = QWidget()
        batch_layout = QVBoxLayout(batch_tab)
        
        # 导入控件组
        import_group = QGroupBox("Excel导入")
        import_layout = QVBoxLayout(import_group)
        
        # 说明标签
        import_label = QLabel(
            "通过Excel文件批量导入监控项，您可以下载模板，填写后导入。\n"
            "注意：模板中包含示例数据，导入前请标记'是否示例'列为'否'或删除示例行。"
        )
        import_label.setWordWrap(True)
        import_layout.addWidget(import_label)
        
        # 按钮组
        buttons_layout = QHBoxLayout()
        
        # 下载模板按钮
        self.template_button = QPushButton("下载Excel模板")
        self.template_button.clicked.connect(self.download_excel_template)
        buttons_layout.addWidget(self.template_button)
        
        # 导入按钮
        self.import_button = QPushButton("从Excel导入")
        self.import_button.clicked.connect(self.import_from_excel)
        buttons_layout.addWidget(self.import_button)
        
        buttons_layout.addStretch()
        import_layout.addLayout(buttons_layout)
        
        batch_layout.addWidget(import_group)
        batch_layout.addStretch()
        
        # 添加批量创建标签页
        tab_widget.addTab(batch_tab, "批量创建")
        
        # 高级标签页
        advanced_tab = QWidget()
        advanced_layout = QFormLayout(advanced_tab)
        
        # 单位
        self.units_edit = QLineEdit()
        advanced_layout.addRow("单位:", self.units_edit)
        
        # 应用集
        self.applications_edit = QLineEdit()
        self.applications_edit.setPlaceholderText("应用集名称，多个用逗号分隔")
        advanced_layout.addRow("应用集:", self.applications_edit)
        
        # 预处理
        self.preprocessing_edit = QTextEdit()
        self.preprocessing_edit.setPlaceholderText("预处理步骤，JSON格式")
        advanced_layout.addRow("预处理:", self.preprocessing_edit)
        
        # 添加高级标签页
        tab_widget.addTab(advanced_tab, "高级设置")
        
        # 设置标签页比例更小，与触发器对话框保持一致
        main_layout.addWidget(tab_widget, 1)
        
        # 添加按钮
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        main_layout.addWidget(button_box)
        
        # 设置对话框属性
        self.setLayout(main_layout)
        
        # 连接信号槽
        self.type_combo.currentIndexChanged.connect(self.on_type_changed)
        
        # 根据第一个主机的端口自动设置客户端类型
        if first_host_port:
            if first_host_port == "161":
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    logger.info(f"基于端口自动设置客户端类型为SNMP 代理，端口号: {first_host_port}")
            elif first_host_port == "10050":
                # 查找Zabbix Agent项在下拉列表中的索引
                zabbix_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 0:  # Zabbix Agent的type_id是0
                        zabbix_agent_index = i
                        break
                
                if zabbix_agent_index >= 0:
                    # 设置为Zabbix Agent
                    self.type_combo.setCurrentIndex(zabbix_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    logger.info(f"基于端口自动设置客户端类型为Zabbix Agent，端口号: {first_host_port}")
        
        # 自动选择表格中的第一行，触发选择事件
        if len(self.hosts) > 0:
            self.host_table.selectRow(0)
            logger.info("自动选择第一个主机")
            # 如果表格中第一个主机是SNMP设备（端口161），自动触发SNMP设置
            if port_161_found:
                logger.info("检测到SNMP设备，自动设置为SNMP 代理")
    
    def on_type_changed(self):
        """当监控项类型改变时的处理函数"""
        # 获取当前选择的类型ID
        type_id = self.type_combo.currentData()
        
        # SNMP类型ID为: 20 - SNMP agent; 17 - SNMP trap
        is_snmp_type = type_id in [20, 17]
        
        # 显示或隐藏SNMP配置区域
        self.snmp_group.setVisible(is_snmp_type)
        
        # 如果不是SNMP类型，隐藏SNMPv3配置区域
        if not is_snmp_type and hasattr(self, 'snmpv3_group'):
            self.snmpv3_group.setVisible(False)
            # 重置SNMP版本标签
            if hasattr(self, 'snmp_version_label'):
                self.snmp_version_label.setText("未选择SNMP设备")
                self.snmp_version_label.setStyleSheet("color: #555555; font-style: italic;")
            return
            
        # 如果是SNMP类型，检查主机接口是否支持SNMPv3
        if is_snmp_type and hasattr(self, 'snmpv3_group'):
            # 获取当前选择的主机
            selected_items = self.host_table.selectedIndexes()
            if selected_items:
                selected_row = selected_items[0].row()
                selected_host_id = self.host_table.item(selected_row, 0).text()
                
                # 检查表格中是否已有SNMP版本信息
                has_snmp_version = False
                if self.host_table.columnCount() > 5:  # 确保SNMP版本列存在
                    snmp_version_item = self.host_table.item(selected_row, 5)
                    if snmp_version_item and snmp_version_item.text():
                        has_snmp_version = True
                        snmp_version = snmp_version_item.text()
                        
                        # 如果已经知道是SNMPv3，直接设置相应的UI
                        if "SNMPv3" in snmp_version:
                            self.snmpv3_group.setVisible(True)
                            logger.info(f"已知SNMPv3设备，显示SNMPv3配置区域")
                            return
                
                # 如果表格中没有SNMP版本信息，或者不是SNMPv3，调用检查函数
                if not has_snmp_version:
                    self.check_snmpv3_device(selected_host_id)
    
    def validate_oid(self):
        """验证并处理OID输入"""
        oid = self.oid_edit.text().strip()
        
        # 如果OID为空，不处理
        if not oid:
            return
            
        # 如果当前不是SNMP类型，但输入了OID，切换到SNMP agent类型
        type_id = self.type_combo.currentData()
        if type_id not in [20, 17]:
            # 查找SNMP agent项在下拉列表中的索引
            snmp_agent_index = -1
            for i in range(self.type_combo.count()):
                if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                    snmp_agent_index = i
                    break
            
            if snmp_agent_index >= 0:
                # 切换到SNMP agent类型
                self.type_combo.setCurrentIndex(snmp_agent_index)
        
        # 不再自动更新键值
        # self.update_snmp_key(oid)
    
    def on_key_changed(self):
        """当键值改变时的处理函数"""
        key = self.key_edit.text().strip()
        
        # 如果键值为空，不处理
        if not key:
            return
            
        # 检查是否是SNMP格式键值
        if key.startswith("snmp.get[") or key.startswith("snmpget["):
            # 尝试提取OID
            try:
                # 提取括号中的内容
                oid_start = key.find("[") + 1
                oid_end = key.rfind("]")
                if oid_start > 0 and oid_end > oid_start:
                    oid = key[oid_start:oid_end]
                    
                    # 如果有逗号分隔的参数，仅取第一部分
                    if "," in oid:
                        oid = oid.split(",")[0]
                    
                    # 如果OID不同，更新OID输入框
                    if oid != self.oid_edit.text():
                        self.oid_edit.setText(oid)
                    
                    # 如果当前不是SNMP类型，切换到SNMP agent类型
                    type_id = self.type_combo.currentData()
                    if type_id not in [20, 17]:
                        # 查找SNMP agent项在下拉列表中的索引
                        snmp_agent_index = -1
                        for i in range(self.type_combo.count()):
                            if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                                snmp_agent_index = i
                                break
                        
                        if snmp_agent_index >= 0:
                            # 切换到SNMP agent类型
                            self.type_combo.setCurrentIndex(snmp_agent_index)
            except Exception as e:
                logger.warning(f"从键值提取OID时出错: {e}")
                
    def update_snmp_key(self, oid):
        """根据OID更新SNMP键值 - 此方法保留但不再自动调用，仅供手动调用"""
        if not oid:
            return
            
        # 确保OID以点开头
        if not oid.startswith("."):
            oid = "." + oid
            
        # 构建正确的SNMP键值 - 所有SNMP类型使用相同的键值格式
        type_id = self.type_combo.currentData()
        if type_id in [20, 17]:  # 20 - SNMP agent; 17 - SNMP trap
            key = f"snmp.get[{oid}]"
            # 更新键值
            self.key_edit.setText(key)
            
    def on_host_selection_changed(self):
        """当选择的主机变更时的处理函数"""
        selected_items = self.host_table.selectedIndexes()
        if not selected_items:
            return
            
        selected_row = selected_items[0].row()
        selected_host_id = self.host_table.item(selected_row, 0).text()
        selected_port = self.host_table.item(selected_row, 4).text()
        
        # 检查是否有明确的端口记录
        if selected_port:
            # 根据端口号设置客户端类型
            if selected_port == "10050":
                logger.info(f"主机 {selected_host_id} 使用端口 10050，设置为Zabbix Agent")
                # 查找Zabbix Agent项在下拉列表中的索引
                zabbix_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 0:  # Zabbix Agent的type_id是0
                        zabbix_agent_index = i
                        break
                
                if zabbix_agent_index >= 0:
                    # 设置为Zabbix Agent
                    self.type_combo.setCurrentIndex(zabbix_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    return  # 端口已确定，无需进一步检查
            elif selected_port == "161":
                logger.info(f"主机 {selected_host_id} 使用端口 161，设置为SNMP 代理")
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    
                    # 检查是否是SNMPv3设备
                    self.check_snmpv3_device(selected_host_id)
                    return  # 端口已确定，无需进一步检查
                    
        # 如果没有明确的端口信息，检查主机是否有SNMP接口
        try:
            # 获取主机的接口
            host_interfaces = self.api.get_host_interfaces(selected_host_id)
            
            # 首先查找SNMP接口（类型为2）
            has_snmp_interface = False
            for interface in host_interfaces:
                if interface.get('type') == '2':  # SNMP接口
                    has_snmp_interface = True
                    # 顺便记录端口信息
                    port = interface.get('port')
                    if port:
                        logger.info(f"发现SNMP接口，端口号: {port}")
                        # 更新表格中的端口显示
                        self.host_table.item(selected_row, 4).setText(port)
                        if port == "161":
                            self.host_table.item(selected_row, 4).setBackground(QColor(230, 230, 255))  # 淡蓝色
                    
                    # 检查SNMP版本
                    details = interface.get('details', {})
                    if isinstance(details, str):
                        try:
                            details = json.loads(details)
                        except json.JSONDecodeError:
                            details = {}
                    
                    version = details.get('version')
                    if version:
                        snmp_version = f"SNMPv{version}"
                        # 获取SNMP版本
                        if version == '3':
                            auth_protocol = details.get('authprotocol', '')
                            priv_protocol = details.get('privprotocol', '')
                            security_name = details.get('securityname', '')
                            
                            auth_info = []
                            if security_name:
                                auth_info.append(f"用户:{security_name}")
                            if auth_protocol:
                                auth_info.append(f"认证:{auth_protocol.upper()}")
                            if priv_protocol:
                                auth_info.append(f"加密:{priv_protocol.upper()}")
                            
                            if auth_info:
                                snmp_version += f" ({', '.join(auth_info)})"
                        
                        # 更新表格中的SNMP版本显示
                        snmp_version_item = QTableWidgetItem(snmp_version)
                        if "SNMPv3" in snmp_version:
                            snmp_version_item.setBackground(QColor(255, 230, 210))  # 淡橙色 - SNMPv3
                            snmp_version_item.setForeground(QColor(170, 0, 0))      # 深红色文字
                            
                            # 更新SNMP版本信息标签
                            self.snmp_version_label.setText(snmp_version)
                            self.snmp_version_label.setStyleSheet("color: #990000; font-weight: bold;")
                        elif "SNMPv2" in snmp_version:
                            snmp_version_item.setBackground(QColor(210, 230, 255))  # 淡蓝色 - SNMPv2
                            
                            # 更新SNMP版本信息标签
                            self.snmp_version_label.setText(snmp_version)
                            self.snmp_version_label.setStyleSheet("color: #000099; font-weight: bold;")
                        self.host_table.setItem(selected_row, 5, snmp_version_item)
                    break
            
            # 如果没有SNMP接口，检查是否有Zabbix Agent接口（类型为1）
            if not has_snmp_interface:
                for interface in host_interfaces:
                    if interface.get('type') == '1':  # Zabbix Agent接口
                        # 记录端口信息
                        port = interface.get('port')
                        if port:
                            logger.info(f"发现Zabbix Agent接口，端口号: {port}")
                            # 更新表格中的端口显示
                            self.host_table.item(selected_row, 4).setText(port)
                            if port == "10050":
                                self.host_table.item(selected_row, 4).setBackground(QColor(230, 255, 230))  # 淡绿色
                        break
                    
            # 如果有SNMP接口，自动设置客户端类型为SNMP 代理
            if has_snmp_interface:
                logger.info(f"检测到主机 {selected_host_id} 有SNMP接口，自动设置为SNMP 代理")
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 触发类型变更事件，以便更新UI
                    self.on_type_changed()
                    
                    # 检查是否是SNMPv3设备
                    self.check_snmpv3_device(selected_host_id)
        except Exception as e:
            logger.error(f"检查主机接口时出错: {str(e)}")
    
    def download_excel_template(self):
        """下载Excel模板"""
        if not PANDAS_AVAILABLE:
            QMessageBox.warning(self, "功能不可用", "未安装pandas库，无法使用Excel功能")
            return
            
        # 打开保存文件对话框
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存Excel模板", "监控项模板.xlsx", "Excel文件 (*.xlsx)"
        )
        
        if not file_path:
            return  # 用户取消了保存
            
        try:
            # 创建数据结构 - 添加示例数据
            data = {
                "监控项名称": ["系统启动时间", "内存使用率"],
                "键值": ["system.uptime", "vm.memory.util"],
                "类型": ["Zabbix 采集器", "Zabbix 采集器"],
                "OID": ["", ""],  # 添加OID列
                "数据类型": ["数值(无符号整数)", "数值(浮点)"],
                "更新间隔": ["60s", "120s"],
                "单位": ["uptime", "%"],
                "描述": ["系统启动时间", "内存使用率"],
                "是否示例": ["是", "是"]  # 添加是否示例列
            }
            
            # 创建DataFrame并保存为Excel
            df = pd.DataFrame(data)
            df.to_excel(file_path, index=False)
            
            QMessageBox.information(
                self, 
                "下载成功", 
                f"Excel模板已保存到: {file_path}"
            )
            
        except Exception as e:
            logger.error(f"生成Excel模板失败: {e}")
            QMessageBox.critical(self, "下载失败", f"生成Excel模板失败: {e}")
    
    def import_from_excel(self):
        """从Excel导入监控项"""
        if not PANDAS_AVAILABLE:
            QMessageBox.warning(
                self, 
                "导入失败", 
                "导入功能需要pandas库支持，请安装pandas库后再试\n安装命令: pip install pandas openpyxl"
            )
            return
        
        # 检查是否选择了主机
        if not self.hosts:
            QMessageBox.warning(self, "导入失败", "请先选择至少一个主机")
            return
        
        # 打开文件对话框
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel文件 (*.xlsx *.xls)"
        )
        
        if not file_path:
            return  # 用户取消了选择
        
        try:
            # 读取Excel文件
            df = pd.read_excel(file_path)
            
            # 检查必要的列是否存在
            required_columns = ["监控项名称", "键值", "类型", "数据类型", "更新间隔"]
            missing_columns = [col for col in required_columns if col not in df.columns]
            
            if missing_columns:
                QMessageBox.warning(
                    self, 
                    "导入失败", 
                    f"Excel文件缺少必要的列: {', '.join(missing_columns)}"
                )
                return
            
            # 准备导入项
            items = []
            skipped_examples = 0
            
            for _, row in df.iterrows():
                # 检查是否是示例数据
                if "是否示例" in df.columns:
                    # 如果存在"是否示例"列，检查其值
                    if pd.notna(row["是否示例"]) and str(row["是否示例"]).lower() in ["是", "yes", "true", "1", "示例"]:
                        skipped_examples += 1
                        continue
                
                # 检查必填字段
                if pd.isna(row["监控项名称"]) or pd.isna(row["键值"]):
                    continue
                
                # 处理类型
                item_type = 0  # 默认为Zabbix Agent
                if not pd.isna(row["类型"]):
                    # 类型名称与ID的映射
                    type_name = str(row["类型"])
                    for type_id, name in self.item_types.items():
                        if type_name == name:
                            item_type = type_id
                            break
                
                # 处理键值 - 如果是SNMP类型，检查键值格式
                key = str(row["键值"]) if not pd.isna(row["键值"]) else ""
                
                # 特别处理SNMP监控项
                if item_type in [20, 17]:  # SNMP agent, SNMP trap
                    # 如果键值不是SNMP格式，检查是否有OID列
                    if not (key.startswith("snmp.get[") or key.startswith("snmpget[") or "snmp" in key.lower()):
                        oid = None
                        # 查找OID列
                        if "OID" in df.columns and not pd.isna(row["OID"]):
                            oid = str(row["OID"])
                            # 构建正确的SNMP键值
                            key = f"snmp.get[{oid}]"
                        else:
                            # 如果没有OID列，尝试从键值中提取OID
                            if key.startswith(".") and all(c.isdigit() or c == '.' for c in key):
                                # 键值本身看起来就是一个OID
                                key = f"snmp.get[{key}]"
                            elif key == "":
                                # 如果键值为空，跳过该项
                                logger.warning(f"跳过行 {_+1}：SNMP监控项缺少键值和OID")
                                continue
                
                # 处理数据类型
                value_type = 0  # 默认为数值(浮点)
                if not pd.isna(row["数据类型"]):
                    # 数据类型名称与ID的映射
                    value_type_name = str(row["数据类型"])
                    for type_id, name in self.value_types.items():
                        if value_type_name == name:
                            value_type = type_id
                            break
                
                # 处理更新间隔
                delay = 60  # 默认60秒
                if not pd.isna(row["更新间隔"]):
                    try:
                        delay_value = str(row["更新间隔"])
                        # 去掉后缀"s"并转换为整数
                        if delay_value.endswith("s"):
                            delay = int(delay_value[:-1])
                        else:
                            delay = int(delay_value)
                    except (ValueError, TypeError):
                        pass
                
                # 对每个选中的主机创建监控项
                for host in self.hosts:
                    host_id = host.get("hostid")
                    if not host_id:
                        continue
                    
                    # 获取主机的接口ID
                    host_interfaces = self.api.get_host_interfaces(host_id)
                    interface_id = None
                    
                    # 查找合适的接口
                    if host_interfaces and len(host_interfaces) > 0:
                        # 根据监控项类型选择合适的接口类型
                        # 0, 7 - Zabbix Agent 类型需要类型为1的接口
                        # 20, 17 - SNMP 类型需要类型为2的接口
                        # 12 - IPMI 类型需要类型为3的接口
                        # 16 - JMX 类型需要类型为4的接口
                        
                        required_interface_type = None
                        if item_type in [0, 7]:  # Zabbix Agent
                            required_interface_type = '1'
                        elif item_type in [20, 17]:  # SNMP
                            required_interface_type = '2'
                        elif item_type == 12:  # IPMI
                            required_interface_type = '3'
                        elif item_type == 16:  # JMX
                            required_interface_type = '4'
                        
                        # 首先查找对应类型的主接口
                        if required_interface_type:
                            for interface in host_interfaces:
                                if interface.get('type') == required_interface_type and interface.get('main') == '1':
                                    interface_id = interface.get('interfaceid')
                                    break
                            
                            # 如果没有找到对应类型的主接口，查找任何对应类型的接口
                            if not interface_id:
                                for interface in host_interfaces:
                                    if interface.get('type') == required_interface_type:
                                        interface_id = interface.get('interfaceid')
                                        break
                        
                        # 如果找不到对应类型的接口或无需特定类型接口，使用主接口
                        if not interface_id:
                            for interface in host_interfaces:
                                if interface.get('main') == '1':
                                    interface_id = interface.get('interfaceid')
                                    break
                        
                        # 如果还找不到，使用第一个接口
                        if not interface_id and host_interfaces:
                            interface_id = host_interfaces[0].get('interfaceid')
                    
                    # 如果没有找到接口ID，跳过该主机
                    if not interface_id:
                        logger.warning(f"主机 {host.get('name')} (ID: {host_id}) 没有可用接口，跳过创建监控项")
                        continue

                    # 获取监控项类型 - 不再进行类型修正，直接使用选择的类型
                    item_type = self.type_combo.currentData()
                    
                    # 创建监控项配置
                    item = {
                        "hostid": host_id,
                        "name": row["监控项名称"],
                        "key_": key,
                        "type": item_type,  # 使用原始类型，不需要修正
                        "value_type": value_type,
                        "delay": str(delay) + "s",  # 添加单位后缀"s"
                        "history": "90d",  # 默认90天
                        "trends": "365d",  # 默认365天
                        "interfaceid": interface_id
                    }
                    
                    # 添加SNMP特有参数
                    if item_type in [20, 17]:  # SNMP agent, SNMP trap
                        # 获取SNMP社区
                        community = "public"  # 默认社区名称
                        if "SNMP社区" in df.columns and not pd.isna(row["SNMP社区"]):
                            community = str(row["SNMP社区"])
                        
                        # 设置社区名称
                        item["snmp_community"] = community
                        
                        # 设置OID
                        if "OID" in df.columns and not pd.isna(row["OID"]):
                            item["snmp_oid"] = str(row["OID"])
                        else:
                            # 尝试从键值中提取OID
                            import re
                            oid_match = re.search(r'snmp\.get\[(.*?)\]', key)
                            if oid_match:
                                item["snmp_oid"] = oid_match.group(1)
                            else:
                                # 如果无法提取OID，使用键值作为OID
                                item["snmp_oid"] = key
                    
                    # 处理可选字段
                    if "单位" in df.columns and not pd.isna(row["单位"]):
                        item["units"] = str(row["单位"])
                    
                    if "描述" in df.columns and not pd.isna(row["描述"]):
                        item["description"] = str(row["描述"])
                    
                    items.append(item)
            
            # 调用API创建监控项
            if not items:
                message = "没有有效的监控项需要创建"
                if skipped_examples > 0:
                    message += f"\n已跳过 {skipped_examples} 行示例数据"
                QMessageBox.warning(self, "导入失败", message)
                return
            
            result = self.api.create_items(items)
            
            # 构建成功消息
            success_message = f"成功导入 {len(result.get('itemids', []))} 个监控项"
            if skipped_examples > 0:
                success_message += f"\n已自动跳过 {skipped_examples} 行示例数据"
                
            QMessageBox.information(self, "导入成功", success_message)
            super().accept()  # 关闭对话框
            
        except Exception as e:
            logger.error(f"从Excel导入监控项失败: {e}")
            QMessageBox.critical(self, "导入失败", f"从Excel导入监控项失败: {e}")
    
    def show_oid_help(self):
        """显示OID帮助信息"""
        help_text = """
<h3>SNMP OID 格式说明</h3>
<p>OID(对象标识符)是一个用于唯一标识SNMP管理对象的数字序列。</p>

<h4>格式要求:</h4>
<ul>
<li>以点(.)开头</li>
<li>由数字和点组成</li>
<li>最常见的OID以.1.3.6.1开头</li>
<li>例如: .1.3.6.1.2.1.1.1.0 表示系统描述</li>
</ul>

<h4>获取OID的方法:</h4>
<ol>
<li>使用snmpwalk工具: <pre>snmpwalk -v 2c -c public &lt;主机IP&gt; .</pre></li>
<li>使用snmpget工具查询特定OID: <pre>snmpget -v 2c -c public &lt;主机IP&gt; .1.3.6.1.2.1.1.1.0</pre></li>
<li>使用MIB浏览器工具</li>
</ol>
        """
        
        QMessageBox.information(self, "SNMP OID 帮助", help_text)
    
    def load_complete_host_info(self):
        """预先加载所有主机的完整信息"""
        try:
            # 获取所有主机ID
            hostids = [host.get('hostid') for host in self.hosts if host.get('hostid')]
            
            if not hostids:
                logger.warning("警告：没有找到任何主机ID")
                return
                
            logger.info(f"正在预先获取 {len(hostids)} 台主机的完整信息...")
            
            try:
                # 直接使用JSON-RPC调用获取完整主机信息
                if hasattr(self.api, 'auth') and hasattr(self.api, 'url'):
                    import requests
                    json_request = {
                        "jsonrpc": "2.0",
                        "method": "host.get",
                        "params": {
                            "hostids": hostids,
                            "output": ["hostid", "host", "name"]
                        },
                        "auth": self.api.auth,
                        "id": 0
                    }
                    
                    url = self.api.url
                    headers = {'Content-Type': 'application/json-rpc'}
                    r = requests.post(url, json=json_request, headers=headers)
                    response = r.json()
                    
                    if "result" in response and response["result"]:
                        host_data = response["result"]
                        logger.info(f"成功获取 {len(host_data)} 台主机的完整信息")
                        
                        # 建立映射关系
                        for host in host_data:
                            hostid = host.get("hostid")
                            technical_name = host.get("host")
                            visible_name = host.get("name")
                            
                            if hostid:
                                self.host_info_map[hostid] = host
                            
                            if visible_name and technical_name:
                                self.name_to_host_map[visible_name] = technical_name
                                logger.info(f"映射: 可见名称 '{visible_name}' -> 技术名称 '{technical_name}'")
                        
                        # 打印主机信息以便调试
                        for host in self.hosts:
                            hostid = host.get("hostid")
                            visible_name = host.get("name", "")
                            original_tech_name = host.get("host", "")
                            
                            if hostid in self.host_info_map:
                                technical_name = self.host_info_map[hostid].get("host", "")
                                logger.info(f"主机信息: ID={hostid}, 原始技术名称={original_tech_name}, 查询到的技术名称={technical_name}, 可见名称={visible_name}")
                                
                                # 更新原始host对象的host字段，确保后续处理使用正确的技术名称
                                if not original_tech_name and technical_name:
                                    host["host"] = technical_name
                                    logger.info(f"已更新主机 {visible_name} 的技术名称为 {technical_name}")
                            else:
                                logger.warning(f"警告: 无法找到主机 ID={hostid}, 可见名称={visible_name} 的完整信息")
                # 如果上面的方法失败，尝试使用API的do_request方法
                elif hasattr(self.api, 'do_request'):
                    response = self.api.do_request('host.get', {
                        'hostids': hostids,
                        'output': ["hostid", "host", "name"]
                    })
                    
                    if isinstance(response, dict) and "result" in response and response["result"]:
                        host_data = response["result"]
                        logger.info(f"成功获取 {len(host_data)} 台主机的完整信息")
                        
                        # 建立映射关系
                        for host in host_data:
                            hostid = host.get("hostid")
                            technical_name = host.get("host")
                            visible_name = host.get("name")
                            
                            if hostid:
                                self.host_info_map[hostid] = host
                            
                            if visible_name and technical_name:
                                self.name_to_host_map[visible_name] = technical_name
                        
                        # 更新原始host对象
                        for host in self.hosts:
                            hostid = host.get("hostid")
                            if hostid in self.host_info_map:
                                tech_name = self.host_info_map[hostid].get("host", "")
                                if not host.get("host") and tech_name:
                                    host["host"] = tech_name
            except Exception as api_err:
                logger.error(f"通过API获取主机完整信息失败: {str(api_err)}")
        except Exception as e:
            logger.error(f"加载主机完整信息时出错: {str(e)}") 
    
    def accept(self):
        """确认按钮处理函数"""
        try:
            # 检查必填字段
            if not self.name_edit.text():
                QMessageBox.warning(self, "验证失败", "监控项名称不能为空")
                return
            
            if not self.key_edit.text():
                QMessageBox.warning(self, "验证失败", "监控项键值不能为空")
                return
            
            # 检查SNMP配置
            item_type = self.type_combo.currentData()
            if item_type in [20, 17]:  # SNMP agent, SNMP trap
                if not self.oid_edit.text():
                    QMessageBox.warning(self, "验证失败", "使用SNMP类型时，OID不能为空")
                    return
                
                # 不再自动更新键值
                # self.update_snmp_key(self.oid_edit.text())
            
            # 构建监控项参数
            items = []
            for host in self.hosts:
                host_id = host.get("hostid")
                if not host_id:
                    continue
                
                # 获取主机的接口ID
                host_interfaces = self.api.get_host_interfaces(host_id)
                interface_id = None
                
                # 查找合适的接口
                if host_interfaces and len(host_interfaces) > 0:
                    # 获取当前选择的监控项类型
                    item_type = self.type_combo.currentData()
                    
                    # 根据监控项类型选择合适的接口类型
                    # 0, 7 - Zabbix Agent 类型需要类型为1的接口
                    # 20, 17 - SNMP 类型需要类型为2的接口
                    # 12 - IPMI 类型需要类型为3的接口
                    # 16 - JMX 类型需要类型为4的接口
                    
                    required_interface_type = None
                    if item_type in [0, 7]:  # Zabbix Agent
                        required_interface_type = '1'
                    elif item_type in [20, 17]:  # SNMP
                        required_interface_type = '2'
                    elif item_type == 12:  # IPMI
                        required_interface_type = '3'
                    elif item_type == 16:  # JMX
                        required_interface_type = '4'
                    
                    # 首先查找对应类型的主接口
                    if required_interface_type:
                        for interface in host_interfaces:
                            if interface.get('type') == required_interface_type and interface.get('main') == '1':
                                interface_id = interface.get('interfaceid')
                                break
                    
                    # 如果找不到对应类型的接口或无需特定类型接口，使用主接口
                    if not interface_id:
                        for interface in host_interfaces:
                            if interface.get('main') == '1':
                                interface_id = interface.get('interfaceid')
                                break
                    
                    # 如果还找不到，使用第一个接口
                    if not interface_id and host_interfaces:
                        interface_id = host_interfaces[0].get('interfaceid')
                
                # 如果没有找到接口ID，跳过该主机
                if not interface_id:
                    logger.warning(f"主机 {host.get('name')} (ID: {host_id}) 没有可用接口，跳过创建监控项")
                    continue
                
                # 获取监控项类型 - 不再进行类型修正，直接使用选择的类型
                item_type = self.type_combo.currentData()
                
                item = {
                    "hostid": host_id,
                    "name": self.name_edit.text(),
                    "key_": self.key_edit.text(),
                    "type": item_type,  # 使用原始类型，不需要修正
                    "value_type": self.value_type_combo.currentData(),
                    "history": str(self.history_spin.value()) + "d",
                    "trends": str(self.trends_spin.value()) + "d",
                    "description": self.description_edit.text(),
                    "units": self.units_edit.text(),
                    "delay": str(self.delay_spin.value()) + "s",  # 添加单位后缀"s"
                    "interfaceid": interface_id  # 添加接口ID
                }
                
                # 添加SNMP特有参数
                if item_type in [20, 17]:  # SNMP agent, SNMP trap
                    # 添加SNMP社区
                    item["snmp_community"] = self.community_edit.text() or "public"
                    
                    # 添加SNMP OID
                    item["snmp_oid"] = self.oid_edit.text()
                    
                    # 如果SNMPv3配置区域可见，则添加SNMPv3相关参数
                    if self.snmpv3_group.isVisible():
                        # SNMP版本设置为3
                        item["snmp_version"] = 3
                        item["snmpv3_securityname"] = self.snmpv3_security_name_edit.text()
                        item["snmpv3_securitylevel"] = self.snmpv3_security_level_combo.currentData()
                        
                        # 根据安全级别设置不同的参数
                        security_level = self.snmpv3_security_level_combo.currentData()
                        
                        # 如果安全级别要求认证 (authNoPriv或authPriv)
                        if security_level in [1, 2]:
                            # 认证协议
                            auth_protocol = self.snmpv3_auth_protocol_combo.currentData()
                            item["snmpv3_authprotocol"] = auth_protocol or "md5"
                            
                            # 认证密码
                            auth_passphrase = self.snmpv3_auth_passphrase_edit.text()
                            if auth_passphrase:
                                item["snmpv3_authpassphrase"] = auth_passphrase
                        
                        # 如果安全级别要求加密 (authPriv)
                        if security_level == 2:
                            # 加密协议
                            priv_protocol = self.snmpv3_priv_protocol_combo.currentData()
                            item["snmpv3_privprotocol"] = priv_protocol or "des"
                            
                            # 加密密码
                            priv_passphrase = self.snmpv3_priv_passphrase_edit.text()
                            if priv_passphrase:
                                item["snmpv3_privpassphrase"] = priv_passphrase
                
                # 设置应用集
                if self.applications_edit.text():
                    applications = [app.strip() for app in self.applications_edit.text().split(",")]
                    if applications:
                        item["applications"] = applications
                
                # 设置预处理步骤
                if self.preprocessing_edit.toPlainText():
                    try:
                        preprocessing = json.loads(self.preprocessing_edit.toPlainText())
                        if preprocessing and isinstance(preprocessing, list):
                            item["preprocessing"] = preprocessing
                    except json.JSONDecodeError:
                        QMessageBox.warning(self, "验证失败", "预处理步骤格式不正确，请使用JSON格式")
                        return
                
                items.append(item)
            
            # 调用API创建监控项
            if items:
                result = self.api.create_items(items)
                QMessageBox.information(
                    self, 
                    "创建成功", 
                    f"成功创建 {len(result.get('itemids', []))} 个监控项"
                )
                super().accept()
            else:
                QMessageBox.warning(self, "创建失败", "没有可创建的监控项")
                
        except Exception as e:
            logger.error(f"创建监控项失败: {e}")
            QMessageBox.critical(self, "创建失败", f"创建监控项失败: {e}") 

    def check_snmpv3_device(self, hostid):
        """检查主机是否为SNMPv3设备并更新界面"""
        try:
            # 获取主机接口信息
            host_interfaces = self.api.get_host_interfaces(hostid)
            has_snmpv3 = False
            snmp_version = ""
            
            for interface in host_interfaces:
                if interface.get('type') == '2':  # SNMP接口
                    # 检查是否有SNMPv3配置
                    details = interface.get('details', {})
                    if isinstance(details, str):
                        try:
                            details = json.loads(details)
                        except json.JSONDecodeError:
                            details = {}
                    
                    version = details.get('version')
                    if version:
                        snmp_version = f"SNMPv{version}"
                        
                    if version == '3':
                        has_snmpv3 = True
                        
                        # 填充SNMPv3配置
                        security_name = details.get('securityname', '')
                        if security_name:
                            self.snmpv3_security_name_edit.setText(security_name)
                        
                        auth_protocol = details.get('authprotocol', '')
                        if auth_protocol:
                            # 设置认证协议
                            index = 0
                            if auth_protocol == 'sha':
                                index = 1
                            self.snmpv3_auth_protocol_combo.setCurrentIndex(index)
                        
                        auth_passphrase = details.get('authpassphrase', '')
                        if auth_passphrase:
                            self.snmpv3_auth_passphrase_edit.setText(auth_passphrase)
                        
                        priv_protocol = details.get('privprotocol', '')
                        if priv_protocol:
                            # 设置加密协议
                            index = 0
                            if priv_protocol == 'aes':
                                index = 1
                            self.snmpv3_priv_protocol_combo.setCurrentIndex(index)
                        
                        priv_passphrase = details.get('privpassphrase', '')
                        if priv_passphrase:
                            self.snmpv3_priv_passphrase_edit.setText(priv_passphrase)
                        
                        # 添加详细信息到SNMP版本显示
                        auth_info = []
                        if security_name:
                            auth_info.append(f"用户:{security_name}")
                        if auth_protocol:
                            auth_info.append(f"认证:{auth_protocol.upper()}")
                        if priv_protocol:
                            auth_info.append(f"加密:{priv_protocol.upper()}")
                        
                        if auth_info:
                            snmp_version += f" ({', '.join(auth_info)})"
                        
                        logger.info(f"检测到SNMPv3配置，已填充相关参数")
                        
                        # 设置密码框为明文显示
                        self.snmpv3_auth_passphrase_edit.setEchoMode(QLineEdit.Normal)
                        self.snmpv3_priv_passphrase_edit.setEchoMode(QLineEdit.Normal)
                        
                        # 更新SNMP版本信息标签
                        self.snmp_version_label.setText(snmp_version)
                        self.snmp_version_label.setStyleSheet("color: #990000; font-weight: bold;")
                        break
                    else:
                        # 如果是SNMPv2，更新标签
                        if version == '2' or version == '2c':
                            self.snmp_version_label.setText(f"SNMPv{version}")
                            self.snmp_version_label.setStyleSheet("color: #000099; font-weight: bold;")
                            break
            
            # 更新主机表格中的SNMP版本信息
            selected_items = self.host_table.selectedIndexes()
            if selected_items:
                selected_row = selected_items[0].row()
                # 检查是否已有SNMP版本信息
                current_version = self.host_table.item(selected_row, 5).text()
                if not current_version and snmp_version:
                    # 更新SNMP版本显示
                    snmp_version_item = QTableWidgetItem(snmp_version)
                    if "SNMPv3" in snmp_version:
                        snmp_version_item.setBackground(QColor(255, 230, 210))  # 淡橙色 - SNMPv3
                        snmp_version_item.setForeground(QColor(170, 0, 0))       # 深红色文字
                    elif "SNMPv2" in snmp_version:
                        snmp_version_item.setBackground(QColor(210, 230, 255))  # 淡蓝色 - SNMPv2
                    self.host_table.setItem(selected_row, 5, snmp_version_item)
            
            # 根据是否有SNMPv3设置显示或隐藏SNMPv3配置区域
            self.snmpv3_group.setVisible(has_snmpv3)
            logger.info(f"SNMPv3配置区域可见性: {has_snmpv3}")
            
            # 如果使用的是SNMPv3，确保使用SNMP代理作为监控项类型
            if has_snmpv3:
                # 查找SNMP agent项在下拉列表中的索引
                snmp_agent_index = -1
                for i in range(self.type_combo.count()):
                    if self.type_combo.itemData(i) == 20:  # SNMP agent的type_id是20
                        snmp_agent_index = i
                        break
                
                if snmp_agent_index >= 0:
                    # 设置为SNMP agent
                    self.type_combo.setCurrentIndex(snmp_agent_index)
                    # 确保SNMP配置区域可见
                    self.snmp_group.setVisible(True)
            
            return has_snmpv3
        
        except Exception as e:
            logger.error(f"检查SNMPv3配置时出错: {str(e)}")
            return False 